﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MLForgeSharp.Models.UnsupervisedLearningModels.Clustering
{
    /// <summary>
    /// k-means聚类
    /// </summary>
    public class kMeansModel
    {
        private double[][] data; // 数据集
        private int k; // 簇的数量
        private int maxIterations; // 最大迭代次数
        private double[][] centroids; // 簇中心
        private int[] labels; // 每个数据点的簇标签

        public kMeansModel(int k = 2, int maxIterations = 100)
        {
            this.k = k;
            this.maxIterations = maxIterations;
        }

        // 计算欧氏距离
        private double EuclideanDistance(double[] a, double[] b)
        {
            double sum = 0.0;
            for (int i = 0; i < a.Length; i++)
            {
                sum += Math.Pow(a[i] - b[i], 2);
            }
            return Math.Sqrt(sum);
        }

        // 初始化簇中心
        private void InitializeCentroids()
        {
            Random rand = new Random();
            centroids = new double[k][];
            List<int> indices = new List<int>();

            // 随机选择 k 个数据点作为初始簇中心
            while (indices.Count < k)
            {
                int index = rand.Next(data.Length);
                if (!indices.Contains(index))
                {
                    indices.Add(index);
                    centroids[indices.Count - 1] = (double[])data[index].Clone();
                }
            }
        }

        // 分配数据点到最近的簇
        private void AssignLabels()
        {
            labels = new int[data.Length];
            for (int i = 0; i < data.Length; i++)
            {
                double minDistance = double.MaxValue;
                for (int j = 0; j < k; j++)
                {
                    double distance = EuclideanDistance(data[i], centroids[j]);
                    if (distance < minDistance)
                    {
                        minDistance = distance;
                        labels[i] = j;
                    }
                }
            }
        }

        // 更新簇中心
        private void UpdateCentroids()
        {
            int[] counts = new int[k];
            double[][] newCentroids = new double[k][];
            for (int i = 0; i < k; i++)
            {
                newCentroids[i] = new double[data[0].Length];
            }

            // 计算每个簇的新中心
            for (int i = 0; i < data.Length; i++)
            {
                int label = labels[i];
                counts[label]++;
                for (int j = 0; j < data[i].Length; j++)
                {
                    newCentroids[label][j] += data[i][j];
                }
            }

            for (int i = 0; i < k; i++)
            {
                if (counts[i] > 0)
                {
                    for (int j = 0; j < newCentroids[i].Length; j++)
                    {
                        newCentroids[i][j] /= counts[i];
                    }
                }
            }

            centroids = newCentroids;
        }

        // 训练模型
        public void Train(double[][] data)
        {
            this.data = data;
            InitializeCentroids();

            for (int iter = 0; iter < maxIterations; iter++)
            {
                AssignLabels();
                double[][] oldCentroids = (double[][])centroids.Clone();
                UpdateCentroids();

                // 检查是否收敛
                bool converged = true;
                for (int i = 0; i < k; i++)
                {
                    if (EuclideanDistance(oldCentroids[i], centroids[i]) > 1e-6)
                    {
                        converged = false;
                        break;
                    }
                }

                if (converged)
                {
                    break;
                }
            }
        }

        // 获取聚类结果
        public int[] GetLabels()
        {
            return labels;
        }

        // 获取簇中心
        public double[][] GetCentroids()
        {
            return centroids;
        }
    }

    // 示例程序
    public class kMeansModelExample
    {
        public kMeansModelExample()
        {
            // 示例数据
            double[][] data = new double[][]
        {
            new double[] { 1.0, 2.0 },
            new double[] { 1.1, 2.1 },
            new double[] { 1.2, 2.2 },
            new double[] { 10.0, 10.0 },
            new double[] { 10.1, 10.1 },
            new double[] { 10.2, 10.2 }
        };

            // 创建模型
            kMeansModel model = new kMeansModel(k: 2, maxIterations: 100);

            // 训练模型
            model.Train(data);

            // 获取聚类结果
            int[] labels = model.GetLabels();
            double[][] centroids = model.GetCentroids();

            // 打印聚类结果
            for (int i = 0; i < labels.Length; i++)
            {
                System.Console.WriteLine("数据点 (" + data[i][0] + ", " + data[i][1] + ") 属于簇 " + labels[i]);
            }

            // 打印簇中心
            for (int i = 0; i < centroids.Length; i++)
            {
                System.Console.WriteLine("簇中心 " + i + ": (" + centroids[i][0] + ", " + centroids[i][1] + ")");
            }
        }
    }
}
